package org.micro.rbac.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.micro.rbac.core.constant.Global;
import org.slf4j.MDC;
import org.springframework.cglib.beans.BeanMap;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author hongsir   2017-11-03 20:11
 * @apiNote springboot中使用HttpServletRequest的工具类，获取bean对象，客户端信息等...
 */
@Slf4j
public class AppUtil {
    public static final IdUtil ID = new IdUtil(1);

    public static Long newId() {
        return ID.nextId();
    }


    /**
     * 正则表达式匹配指定字符串中间的内容
     *
     * @param content
     * @param regex
     * @return
     */
    public static List<String> subAll(String content, String regex) {
        List<String> list = Lists.newArrayList();
        Pattern pattern = Pattern.compile(regex);
        Matcher m = pattern.matcher(content);
        while (m.find()) {
            list.add(m.group(0));
        }
        return list;
    }

    public static String subChinese(String content) {
        List<String> list = AppUtil.subAll(content, "[\u4E00-\u9FA5]");
        if (ObjectUtil.isEmpty(list)) {
            return null;
        }
        return list.stream().map(String::valueOf).collect(Collectors.joining("", "", ""));
    }

    /**
     * -\[serialNo:(.*?)\]
     * 返回单个字符串，若匹配到多个的话就返回第一个，方法与subAll一样
     *
     * @param content
     * @param regex
     * @return
     */
    public static String subFirst(String content, String regex) {
        Pattern pattern = Pattern.compile(regex);
        Matcher m = pattern.matcher(content);
        if (m.find()) {
            return m.group(1);
        }
        return "";
    }

    public static String getMDC() {
        try {
            String mdc = MDC.get(Global.MDC_SERIAL);
            if (StrUtil.isNotBlank(mdc)) {
                //"-[" + CommonConstant.MDC_SERIAL + ":" + serialNo + "]"
                String regex = "-\\[serialNo:(.*?)\\]";
                return subFirst(mdc, regex);
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    public static void setMDC(String serialNo) {
        if (StrUtil.isNotBlank(serialNo)) {
            if (StrUtil.isNotBlank(MDC.get(Global.MDC_SERIAL))) {
                MDC.remove(Global.MDC_SERIAL);
            }
            MDC.put(Global.MDC_SERIAL, "-[" + Global.MDC_SERIAL + ":" + serialNo + "]");
        }
    }

    public static void clearMDC() {
        if (StrUtil.isNotBlank(MDC.get(Global.MDC_SERIAL))) {
            MDC.remove(Global.MDC_SERIAL);
        }
    }

    public static boolean isDev(String current) {
        return "dev".equals(current);
    }

    public static <T> Map<String, Object> beanToMap(T bean) {
        Map<String, Object> map = Maps.newHashMap();
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(key + "", beanMap.get(key));
            }
        }
        return map;
    }

    /**
     * 将map装换为javabean对象
     *
     * @param map
     * @param bean
     * @return
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    /**
     * 单位大小换算
     * byte(B)>>KB>>MB>>GB>>
     *
     * @param size
     * @return
     */
    public static String calcSize(long size) {
        double unit = 1024;
        StringBuilder bytes = new StringBuilder();
        DecimalFormat format = new DecimalFormat("###.0");
        if (size >= unit * unit * unit) {
            double i = (size / (unit * unit * unit));
            bytes.append(format.format(i)).append("GB");
        } else if (size >= unit * unit) {
            double i = (size / (unit * unit));
            bytes.append(format.format(i)).append("MB");
        } else if (size >= unit) {
            double i = (size / (unit));
            bytes.append(format.format(i)).append("KB");
        } else {
            if (size <= 0) {
                bytes.append("0B");
            } else {
                bytes.append((int) size).append("B");
            }
        }
        return bytes.toString();
    }

    /**
     * 将路由转换成正则
     *
     * @param str 多个用 ',' 隔开
     * @return
     */
    public static Pattern[] initPattern(String str) {
        Pattern[] patterns = null;
        if (StrUtil.isNotBlank(str)) {
            String split = ",";
            String flag = "\\*";
            String replace = ".*";
            String[] arr = str.split(split);
            patterns = new Pattern[arr.length];
            for (int i = 0; i < arr.length; i++) {
                patterns[i] = Pattern.compile(arr[i].trim().replaceAll(flag, replace));
            }
        }
        return patterns;
    }

    public static Pattern[] initPattern(String... str) {
        Pattern[] patterns = null;
        if (ObjectUtil.isNotEmpty(str)) {
            String flag = "\\*";
            String replace = ".*";
            patterns = new Pattern[str.length];
            for (int i = 0; i < str.length; i++) {
                patterns[i] = Pattern.compile(str[i].trim().replaceAll(flag, replace));
            }
        }
        return patterns;
    }

    public static boolean matcher(Pattern[] patterns, String matcherUrl) {
        if (ObjectUtil.isEmpty(patterns)) {
            return true;
        }
        if (StrUtil.isBlank(matcherUrl)) {
            return false;
        }
        for (Pattern pat : patterns) {
            if (pat.matcher(matcherUrl).matches()) {
                return true;
            }
        }
        return false;
    }

    public static String calcTime(long start, long end) {
        String result = "";
        // 时间差,单位:毫秒
        long cha = end - start;
        // 得到秒
        long second = cha / 1000;
        // 得到剩余的毫秒
        long millisecond = cha % 1000;
        // 得到分
        long minute = second / 60;
        second = second % 60;
        result = minute + "′" + second + "″" + millisecond;
        return result;
    }


    public static <T, U> U beanCopy(T source, Class<U> targetClazz, String... ignoreField) {
        String jsonStr = JSON.toJSONString(source);
        U result = JSON.parseObject(jsonStr, targetClazz);
        if (result != null && ignoreField != null && ignoreField.length > 0) {
            for (String field : ignoreField) {
                if (ReflectUtil.hasField(targetClazz, field)) {
                    ReflectUtil.setFieldValue(result, field, null);
                }
            }
        }
        return result;
    }

    public static <T1, T2> void beanCopy(T1 source, T2 target, Class<T2> targetClazz, String... ignoreField) {
        T2 temp = beanCopy(source, targetClazz, ignoreField);
        Field[] fields = ReflectUtil.getFields(source.getClass());
        for (Field field : fields) {
            if (Modifier.isFinal(field.getModifiers())) {
                continue;
            }
            if (ReflectUtil.hasField(target.getClass(), field.getName())) {
                Object value = ReflectUtil.getFieldValue(temp, field.getName());
                ReflectUtil.setFieldValue(target, field.getName(), value);
            }
        }
    }

    public static String getFiledValue(Object obj, String... field) {
        StringBuilder value = new StringBuilder();
        for (String s : field) {
            // 如果实在是特别复杂的数据直接用JSON处理,全部序列化成Str
            Object v = ReflectUtil.getFieldValue(obj, s);
            if (ReflectUtil.getField(obj.getClass(), s).getType() == Date.class) {
                value.append(DateUtil.format((Date) v, Global.DATETIME_FORMAT)).append("_");
            } else {
                value.append(v.toString()).append("_");
            }
        }
        return value.toString();
    }


    public static String subIgnore(String str, int len, String chars) {
        if (str.length() <= len) {
            return str;
        }
        return str.substring(0, len) + StrUtil.blankToDefault(chars, "...");
    }

}
